package org.tech4j.edi.base.executor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tech4j.edi.api.RetryExecutor;
import org.tech4j.edi.api.RetryExecutorChain;
import org.tech4j.edi.api.context.RetryContext;
import org.tech4j.edi.base.exception.EdiException;
import org.tech4j.edi.common.RetryHandle;
import org.tech4j.edi.common.entity.RetryBizConfig;
import org.tech4j.edi.common.entity.RetryBizRecord;
import org.tech4j.edi.common.enums.RetryStatusEnum;

import java.util.Calendar;
import java.util.Date;
import java.util.Objects;

/**
 * @program: tech4j
 * @description:
 * @author: YuKai Fan
 * @create: 2025/3/7 20:47
 **/
public class FilterRetryExecutor implements RetryExecutor {
    private static final Logger log = LoggerFactory.getLogger(FilterRetryExecutor.class);

    @Override
    public void execute(RetryContext context, RetryExecutorChain chain) {
        RetryBizRecord retryBizRecord = context.getRetryBizRecord();
        RetryBizConfig retryBizConfig = context.getRetryBizConfig();

        RetryHandle retryHandle = context.getRetryHandle();
        if (Objects.isNull(retryHandle)) {
            throw new EdiException(String.format("[%s]重试处理器为空", retryBizRecord.getBizType()));
        }

        retryFilter(retryBizConfig, retryBizRecord);
        filterLastOpTime(retryBizConfig, retryBizRecord.getLastOpTime());

        if (retryBizConfig.getRetryModel().isHand()) {
            log.warn("[{}]重试配置为手动重试, 不继续判断, 直接执行", retryBizConfig.getBizType());
            chain.execute(context);
            return;
        }

        // 如果当前状态为初始, 则直接执行
        if (retryBizRecord.getRecordStatus() == RetryStatusEnum.RETRY_INIT) {
            chain.execute(context);
            return;
        }

        // 最近执行时间如果为空, 则表示第一次执行, 也直接放行
        if (retryBizRecord.getLastOpTime() == null) {
            chain.execute(context);
            return;
        }
        chain.execute(context);
    }

    private void retryFilter(RetryBizConfig retryBizConfig, RetryBizRecord retryBizRecord) {
        if (Objects.isNull(retryBizConfig)) {
            throw new EdiException(String.format("[%s]重试配置为空", retryBizRecord.getBizType()));
        }
        if (RetryStatusEnum.RETRY_ING == retryBizRecord.getRecordStatus()) {
            throw new EdiException(String.format("当前记录[%s]不能重试，正在重试中", retryBizRecord.getId()));
        }
        // 重试配置是否可用
        if (Boolean.FALSE.equals(retryBizConfig.getEnabled())) {
            throw new EdiException(String.format("记录不能重试，[%s]重试配置停用", retryBizConfig.getBizType()));
        }
        if (cannotRetry(retryBizConfig)) {
            throw new EdiException(String.format("记录不能重试，[%s]重试配置最大重试次数为0", retryBizConfig.getBizType()));
        }
        if (retryBizRecord.getRetryTimes() >= retryBizConfig.getMaxRetryTimes()) {
            throw new EdiException(String.format("当前记录[%s]不能重试，重试次数已达到最大值[%s]", retryBizRecord.getId(), retryBizConfig.getMaxRetryTimes()));
        }
    }


    /**
     * 过滤最近操作时间
     *
     * 根据重试配置的 执行间隔参数判断
     *
     * 如果最近操作时间+执行间隔, 没有达到当前时间, 则直接返回
     */
    public void filterLastOpTime(RetryBizConfig retryBizConfig, Date lastOpTime) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(lastOpTime);
        calendar.add(Calendar.MILLISECOND, retryBizConfig.getRetryInterval());
        Date nextOpTime = calendar.getTime();
        if (new Date().before(nextOpTime)) {
            throw new EdiException("记录不能重试，没有达到执行时间");
        }
    }


    private boolean cannotRetry(RetryBizConfig config) {
        return config.getMaxRetryTimes() == 0;
    }

    @Override
    public int getOrder() {
        return EdiExecutorsOrder.RETRY_FILTER.getOrder();
    }
}
